package com.tiny.cqzcp.main;

import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.tiny.cqzcp.main.thread.KlbOneRunnable;
import com.tiny.cqzcp.main.thread.KlbThreeRunnable;
import com.tiny.cqzcp.main.thread.KlbTwoRunnable;
import com.tiny.cqzcp.main.thread.RecommendRunnable;
import com.tiny.cqzcp.pojo.Job;
import com.tiny.cqzcp.pojo.RecNumber;
import com.tiny.cqzcp.pojo.User;
import com.tiny.cqzcp.pojo.UserNumbers;
import com.tiny.cqzcp.pojo.UserOrder;
import com.tiny.cqzcp.pojo.UserWallet;
import com.tiny.cqzcp.pojo.klb.Lottery;
import com.tiny.cqzcp.service.JobService;
import com.tiny.cqzcp.service.OrderService;
import com.tiny.cqzcp.service.RecommendService;
import com.tiny.cqzcp.service.UserService;
import com.tiny.cqzcp.service.klb.KlbLotteryService;
import com.tiny.cqzcp.service.klb.KlbOneService;
import com.tiny.cqzcp.service.klb.KlbThreeService;
import com.tiny.cqzcp.service.klb.KlbTwoService;
import com.tiny.cqzcp.utils.ToolkitUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * @author jmz
 */
public class Analysis {

    private static final Logger log = LogManager.getLogger(Analysis.class);
    private static final int LIST_LEN = 1;
    private static final int KLB_JOB_TYPE = 1;
    private static final String STR_KLB = "KLB";
    private static final String STR_RECOMMEND = "RECOMMEND";
    private static final String STR_RECOMMEND_NEW = "RECOMMENDNEW";
    private static final String LEVEL_USER_GUST = "0";

    private static ApplicationContext context = new FileSystemXmlApplicationContext("classpath:spring-mybatis.xml");

    private static JobService jobService = context.getBean(JobService.class);
    private static RecommendService recService = context.getBean(RecommendService.class);
    private static UserService userService = context.getBean(UserService.class);
    private static KlbLotteryService klbLotteryService = context.getBean(KlbLotteryService.class);
    private static KlbOneService klbOneService = context.getBean(KlbOneService.class);
    private static KlbTwoService klbTwoService = context.getBean(KlbTwoService.class);
    private static KlbThreeService klbThreeService = context.getBean(KlbThreeService.class);
    private static OrderService orderService = context.getBean(OrderService.class);

    private static long SLEEP_TIME = 20000;

    public static void main(String[] args) {
        String mode = args[0];
        //获取系统处理器个数，作为线程池数量
        int nThreads = Runtime.getRuntime().availableProcessors();
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("klb-pool-%d").build();
        if(STR_KLB.equals(mode)){
            while(true){
                // 获取开始时间
                long startTime = System.currentTimeMillis();
                calculationMiss(nThreads,namedThreadFactory);
                // 获取结束时间
                long endTime = System.currentTimeMillis();
                // 输出程序运行时间
                log.info("程序运行时间：" + (endTime - startTime) / 1000 + "s");
                log.info("新一轮数据处理完成！休眠:" + (SLEEP_TIME / 1000) + "s!");
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    log.error(ToolkitUtil.printStackTraceToString(e));
                }
            }
        }else if(STR_RECOMMEND.equals(mode)){
            for(int x=0;x<5;x++){
                for(int y=0;y<10;y++){
                    List<String> square = new ArrayList<>();
                    List<String> square1 = new ArrayList<>();
                    List<String> square2 = new ArrayList<>();
                    for(int k=0;k<3;k++){
                        List<String> lists = ToolkitUtil.randomList(80);
                        for(int i=0;i<10;i++){
                            for(int j=0;j<4;j++){
                                int index = j * 10 + i;
                                StringJoiner joiner = new StringJoiner(",");
                                joiner.add(lists.get(index));
                                joiner.add(lists.get(index+20));
                                joiner.add(lists.get(index+40));
                                if(k == 0){
                                    square.add(joiner.toString());
                                }else if(k == 1){
                                    square1.add(joiner.toString());
                                }else{
                                    square2.add(joiner.toString());
                                }
                            }
                            for(int j=0;j<2;j++){
                                int index = j * 10 + i;
                                StringJoiner joiner = new StringJoiner(",");
                                joiner.add(lists.get(index));
                                joiner.add(lists.get(index+30));
                                joiner.add(lists.get(index+60));
                                if(k == 0){
                                    square.add(joiner.toString());
                                }else if(k == 1){
                                    square1.add(joiner.toString());
                                }else{
                                    square2.add(joiner.toString());
                                }
                            }
                        }
                    }
                    List<String> list = new ArrayList<>();
                    for(String s:square){
                        for(String s1:square1){
//                            list.add(s +","+s1);
                            for(String s2:square2){
                                list.add(s +","+s1+","+s2);
                            }
                        }
                    }
                    List<String> result = new ArrayList<>();
                    for(String s : list){
                        String[] array = s.split(",");
                        //排序array
                        int[] intArray = new int[array.length];
                        for(int m=0;m<array.length;m++){
                            int number = Integer.parseInt(array[m]);
                            intArray[m] = number;
                        }
                        Arrays.sort(intArray);
                        StringJoiner joiner = new StringJoiner(",");
                        for(int m=0;m<intArray.length;m++){
                            String number = String.valueOf(intArray[m]);
                            if(intArray[m] < 10){
                                number = "0"+intArray[m];
                            }
                            joiner.add(number);
                        }
                        if(!checkRepeat(intArray)){
                            result.add(joiner.toString());
                        }
                    }
                    Set<String> set = new HashSet<>();
                    for(String s : result){
                        set.add(s);
                    }
                    List<String> winning = new ArrayList<>();
                    List<String> winning1 = new ArrayList<>();
                    List<String> winning2 = new ArrayList<>();
                    List<String> winning3 = new ArrayList<>();
                    List<String> winning4 = new ArrayList<>();
                    List<String> winning5 = new ArrayList<>();
                    List<String> winning6 = new ArrayList<>();
                    String nbr = "01,03,05,09,15,19,21,27,33,40,47,51,53,56,57,58,59,60,70,71";
                    for(String s : set){
                        int k=0;
                        String[] s1 = s.split(",");
                        for(int i=0;i<s1.length;i++){
                            if(nbr.indexOf(s1[i]) > -1){
                                k++;
                            }
                        }
                        if(k == 3){
                            winning.add(s);
                        }
                        if(k == 4){
                            winning1.add(s);
                        }
                        if(k == 5){
                            winning2.add(s);
                        }
                        if(k == 6){
                            winning3.add(s);
                        }
                        if(k == 7){
                            winning4.add(s);
                        }
                        if(k == 8){
                            winning5.add(s);
                        }
                        if(k == 9){
                            winning6.add(s);
                        }
                    }
                    System.out.println(winning.size()+"|"+winning1.size()+"|"+winning2.size()+"|"+winning3.size()
                            +"|"+winning4.size()+"|"+winning5.size()+"|"+winning6.size());
                }
                System.out.println("############################");
            }
        }else if(STR_RECOMMEND_NEW.equals(mode)){
//            calculationRecommend();
            for(int n=0;n<10;n++){
                calculationRecommendNew();
            }
        }else{
            List<Lottery> list = klbLotteryService.selectByParams(-1);
            //手动创建线程池
            ExecutorService pool = new ThreadPoolExecutor(nThreads, 2*nThreads,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
            calculationMiss(pool,list);
        }
    }

    /**
     * @Description  判断数组中是否有重复值
     * @title checkRepeat
     * @date 2021/4/6
     * @auther Administrator
     */
    private static boolean checkRepeat(String[] array){
        Set<String> set = new HashSet<>();
        for(String str : array){
            set.add(str);
        }
        return set.size() != array.length;
    }
    /**
     * @Description 判断数组中是否有重复值
     * @title checkRepeat
     * @date 2021/4/6
     * @auther Administrator
     */
    private static boolean checkRepeat(int[] array){
        Set<Integer> set = new HashSet<>();
        for(int str : array){
            set.add(str);
        }
        return set.size() != array.length;
    }

    /**
     * @Description 计算遗漏
     * @title calculationMiss
     * @date 2021/3/27
     * @auther Administrator
     */
    private static void calculationMiss(int nThreads,ThreadFactory namedThreadFactory){
        //手动创建线程池
        ExecutorService pool = new ThreadPoolExecutor(nThreads, 2*nThreads,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

        // 获取最近一次计算遗漏的期数
        Job job = jobService.queryJobByType(KLB_JOB_TYPE);
        if(job != null){
            String term = job.getJobInfo();
            //获取快乐8最新一条数据
            List<Lottery> list = klbLotteryService.selectByParams(LIST_LEN);
            String newTerm = list.get(0).getLotteryNo();
            String newDate = list.get(0).getLotteryDate();
            //当期号与上一次计算遗漏的期号不同且最新一期的数据入库时间为当前日期，则开始计算最新一期遗漏信息
            if(!term.equals(newTerm) && newDate.startsWith(ToolkitUtil.currentDate())){
                handleData(job,pool,list);
            }
        }
        pool.shutdown();
    }

    private static void calculationRecommendNew(){
        List<String> lists = ToolkitUtil.randomList(80);
        List<String> square = new ArrayList<>();
        for(int i=0;i<10;i++){
            for(int j=0;j<4;j++){
                int index = j * 10 + i;
                StringJoiner joiner = new StringJoiner(",");
                joiner.add(lists.get(index));
                joiner.add(lists.get(index+20));
                joiner.add(lists.get(index+40));
                square.add(joiner.toString());
            }
            for(int j=0;j<2;j++){
                int index = j * 10 + i;
                StringJoiner joiner = new StringJoiner(",");
                joiner.add(lists.get(index));
                joiner.add(lists.get(index+30));
                joiner.add(lists.get(index+60));
                square.add(joiner.toString());
            }
        }
        //大包共计60注
        //拆分2个包，每个包30个
        List<String> list = new ArrayList<>();
        List<String> list1 = new ArrayList<>();
        for(int i=0;i<2;i++){
            for(int j=0;j<30;j++){
                int index = i*10 + j;
                if(i == 0){
                    list.add(square.get(index));
                }else{
                    list1.add(square.get(index));
                }
            }
        }
        List<String> tmp = new ArrayList<>();
        for(String s:list){
            for(String s1:list1){
                tmp.add(s +","+s1);
            }
        }
        List<String> result = new ArrayList<>();
        for(String s : tmp){
            String[] array = s.split(",");
            //排序array
            int[] intArray = new int[array.length];
            for(int m=0;m<array.length;m++){
                int number = Integer.parseInt(array[m]);
                intArray[m] = number;
            }
            Arrays.sort(intArray);
            StringJoiner joiner = new StringJoiner(",");
            for(int m=0;m<intArray.length;m++){
                String number = String.valueOf(intArray[m]);
                if(intArray[m] < 10){
                    number = "0"+intArray[m];
                }
                joiner.add(number);
            }
            if(!checkRepeat(intArray)){
                result.add(joiner.toString());
            }
        }
        Set<String> set = new HashSet<>();
        for(String s : result){
            set.add(s);
        }
        List<String> winning = new ArrayList<>();
        List<String> winning1 = new ArrayList<>();
        List<String> winning2 = new ArrayList<>();
        List<String> winning3 = new ArrayList<>();
        String nbr = "01,03,05,09,15,19,21,27,33,40,47,51,53,56,57,58,59,60,70,71";
        for(String s : set){
            int k=0;
            String[] s1 = s.split(",");
            for(int i=0;i<s1.length;i++){
                if(nbr.indexOf(s1[i]) > -1){
                    k++;
                }
            }
            if(k == 3){
                winning.add(s);
            }
            if(k == 4){
                winning1.add(s);
            }
            if(k == 5){
                winning2.add(s);
            }
            if(k == 6){
                winning3.add(s);
            }
        }
        System.out.println(winning.size()+"|"+winning1.size()+"|"+winning2.size()+"|"+winning3.size());
    }

    /**
     * @Description 计算推荐号
     * @title calculationRECOMMEND
     * @date 2021/3/27
     * @auther Administrator
     */
    private static void calculationRecommend(){
        //计算四码
        for(int k=0;k<20;k++){
            List<String> lists = ToolkitUtil.randomList(80);
            List<String> square = new ArrayList<>();
            //获取3*3矩阵的4个点
            for(int i=0;i<6;i++){
                for(int j=0;j<8;j++){
                    int index = i * 10 + j;
                    StringJoiner joiner = new StringJoiner(",");
                    joiner.add(lists.get(index));
                    joiner.add(lists.get(index+2));
                    joiner.add(lists.get(index+20));
                    joiner.add(lists.get(index+22));
                    square.add(joiner.toString());
                }
            }
            //获取4*4矩阵的4个点
            for(int i=0;i<5;i++){
                for(int j=0;j<7;j++){
                    int index = i * 10 + j;
                    StringJoiner joiner = new StringJoiner(",");
                    joiner.add(lists.get(index));
                    joiner.add(lists.get(index+3));
                    joiner.add(lists.get(index+30));
                    joiner.add(lists.get(index+33));
                    square.add(joiner.toString());
                }
            }
            //获取5*5矩阵的4个点
            for(int i=0;i<4;i++){
                for(int j=0;j<6;j++){
                    int index = i * 10 + j;
                    StringJoiner joiner = new StringJoiner(",");
                    joiner.add(lists.get(index));
                    joiner.add(lists.get(index+4));
                    joiner.add(lists.get(index+40));
                    joiner.add(lists.get(index+44));
                    square.add(joiner.toString());
                }
            }
            List<RecNumber> recNumbers = new ArrayList<>();
            //107注的大包
            String packageId = String.valueOf(System.currentTimeMillis());
            for(String s : square){
                RecNumber recNumber = new RecNumber();
                recNumber.setRnumbersContent(s);
                recNumber.setRnumbersType("0");
                recNumber.setRnumbersStatus(0);
                recNumber.setRnumbersPackage(packageId);
                recNumber.setRnumbersTime(ToolkitUtil.currentDateTime());
                recNumbers.add(recNumber);
            }
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(k == 19){
                recNumbers.clear();
                //拆分5个包，每个包20个，去掉5*5的后7个数据
                for(int i=0;i<5;i++){
                    String smallPackageId = String.valueOf(System.currentTimeMillis());
                    for(int j=0;j<20;j++){
                        int index = i*10 + j;
                        RecNumber recNumber = new RecNumber();
                        recNumber.setRnumbersContent(square.get(index));
                        recNumber.setRnumbersType("1");
                        recNumber.setRnumbersStatus(0);
                        recNumber.setRnumbersPackage(smallPackageId);
                        recNumber.setRnumbersTime(ToolkitUtil.currentDateTime());
                        recNumbers.add(recNumber);
                    }
                    try {
                        Thread.sleep(400);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            if(!recNumbers.isEmpty()){
                recService.batchInsert(recNumbers);
            }
            recNumbers.clear();
        }
        //计算三码
        for(int k=0;k<10;k++){
            List<String> lists = ToolkitUtil.randomList(80);
            List<String> square = new ArrayList<>();
            for(int i=0;i<10;i++){
                for(int j=0;j<4;j++){
                    int index = j * 10 + i;
                    StringJoiner joiner = new StringJoiner(",");
                    joiner.add(lists.get(index));
                    joiner.add(lists.get(index+20));
                    joiner.add(lists.get(index+40));
                    square.add(joiner.toString());
                }
                for(int j=0;j<2;j++){
                    int index = j * 10 + i;
                    StringJoiner joiner = new StringJoiner(",");
                    joiner.add(lists.get(index));
                    joiner.add(lists.get(index+30));
                    joiner.add(lists.get(index+60));
                    square.add(joiner.toString());
                }
            }
            //大包共计60注
            List<RecNumber> recNumbers = new ArrayList<>();
            //拆分2个包，每个包30个
            for(int i=0;i<2;i++){
                String smallPackageId = String.valueOf(System.currentTimeMillis());
                for(int j=0;j<30;j++){
                    int index = i*10 + j;
                    RecNumber recNumber = new RecNumber();
                    recNumber.setRnumbersContent(square.get(index));
                    recNumber.setRnumbersType("2");
                    recNumber.setRnumbersStatus(0);
                    recNumber.setRnumbersPackage(smallPackageId);
                    recNumber.setRnumbersTime(ToolkitUtil.currentDateTime());
                    recNumbers.add(recNumber);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if(!recNumbers.isEmpty()){
                recService.batchInsert(recNumbers);
            }
            recNumbers.clear();
        }
    }

    /**
     * 解析新一期数据
     * @title: handleData
     * @Author: jmz
     * @DateTime: 2021/2/19 11:44
     **/
    private static void handleData(Job job,ExecutorService pool,List<Lottery> list){
        //标记任务开始以及开始时间
        job.setJobStatus(1);
        job.setJobStart(ToolkitUtil.currentDateTime());
        jobService.updateRecord(job);
        //计算遗漏数据
        calculationMiss(pool,list);
        //后续添加推荐号的标记
        judgeRecommend(list.get(0).getLotteryRes(),list.get(0).getLotteryNo());
        //标记任务结束以及结束时间
        job.setJobInfo(list.get(0).getLotteryNo());
        job.setJobStatus(2);
        job.setJobEnd(ToolkitUtil.currentDateTime());
        jobService.updateRecord(job);
        //计算推荐号
        calculationRecommend();
    }

    /**
     * 计算最新一期的遗漏数据
     * @title: calculationMiss
     * @param pool
     * @param list
     * @Author: jmz
     * @DateTime: 2021/2/19 11:37
     **/
    private static void calculationMiss(ExecutorService pool,List<Lottery> list){
        int size = 10;
        List<Lottery> maxTerms = klbLotteryService.selectMaxTerm();
        //一码遗漏计算
        Runnable klbOneRunnable = new KlbOneRunnable(klbOneService, maxTerms, list, 0, 80);
        pool.execute(klbOneRunnable);
        //二码遗漏计算
        for (int n = 0; n < size; n++) {
            Runnable klbTwoRunnable = new KlbTwoRunnable(klbTwoService, maxTerms, list, n * 316, 316);
            pool.execute(klbTwoRunnable);
        }
        //后三连遗漏计算
        for (int n = 0; n < size; n++) {
            Runnable klbThreeRunnable = new KlbThreeRunnable(klbThreeService, maxTerms, list, n * 512, 512);
            pool.execute(klbThreeRunnable);
        }
        //关闭线程池
        pool.shutdown();
        while (true) {
            if (pool.isTerminated()) {
                break;
            }
        }
    }
    /**
     * 推荐号中奖标注
     * @param numbers
     */
    private static void judgeRecommend(String numbers,String term) {
        List<RecNumber> allRecNbs = new ArrayList<>();
        log.info("推荐号中奖标注开始！");
        // 推荐号库内数据
        RecNumber record = new RecNumber();
        record.setRnumbersStatus(-1);
        List<RecNumber> recs = recService.queryRecAllRecords(record);
        for (RecNumber rec : recs) {
            recBasicNumber(rec, numbers, term, allRecNbs);
        }
        if (!allRecNbs.isEmpty()) {
            recService.batchUpdate(allRecNbs);
        }
        allRecNbs.clear();
        //获取订单状态为1的所有订单
        UserOrder userOrder = new UserOrder();
        userOrder.setOrderStatus(1);
        List<UserOrder> orders = orderService.selectByParams(userOrder);
        for(UserOrder order : orders){
            List<UserNumbers> allUserNbs = new ArrayList<>();
            String orderId = order.getOrderId();
            // 用户购买推荐号数据
            UserNumbers uRecord = new UserNumbers();
            uRecord.setNumbersOrderid(orderId);
            List<UserNumbers> uRecs = recService.queryUserAllRecordsByOrderId(uRecord);
            uRecs = recUserNumber(uRecs, numbers, term, allUserNbs);
            if(allUserNbs.size() == 0){
                User user = userService.queryUser(order.getUserTelephone());
                // 退款到相应账号
                Integer wallet = user.getUserWallet();
                user.setUserWallet(user.getUserWallet() + order.getOrderPrice());
                userService.updateUser(user);
                UserWallet uWallet = new UserWallet();
                uWallet.setUserTelephone(order.getUserTelephone());
                uWallet.setWalletMoney(order.getOrderPrice());
                uWallet.setWalletType("RECHARGE");
                uWallet.setWalletDesc("订单：" + uRecs.get(0).getNumbersOrderid() + "未开出，返还用户："
                        + order.getUserTelephone() + "," + order.getOrderPrice() + "元！退款前：" + wallet + "元");
                uWallet.setWalletTime(ToolkitUtil.currentDateTime());
                uWallet.setWalletFlow(System.currentTimeMillis() + "");
                uWallet.setWalletFtype(0);
                uWallet.setWalletStatus(1);
                userService.addUserWallet(uWallet);
                log.info("订单：" + uRecs.get(0).getNumbersOrderid() + "未开出，返还用户："
                        + order.getUserTelephone() + "," + order.getOrderPrice() + "元！退款前：" + wallet + "元");
            }
            recService.batchUpdateUserNumbers(uRecs);
            order.setOrderStatus(2);
            orderService.updateUserOrder(order);
            allUserNbs.clear();
        }
        log.info("推荐号中奖标注结束！");
    }


    /**
     * @Description 标记推荐号库中中奖号码
     * @title recBasicNumber
     * @date 2021/3/15
     * @auther Administrator
     */
    private static void recBasicNumber(RecNumber rec, String numbers,String term,List<RecNumber> allRecNbrs) {
        HashSet<String> set = new HashSet<>(Arrays.asList(numbers.split(",")));
        Integer hits = 3;
        if("0".equals(rec.getRnumbersType())){
            hits = 4;
        }else if("3".equals(rec.getRnumbersType())){
            hits = 5;
        }
        set.retainAll(Arrays.asList(rec.getRnumbersContent().split(",")));
        if (set.size() >= hits) {
            rec.setRnumbersStatus(1);
            rec.setRnumbersTerm(term);
            rec.setRnumbersNbr(numbers);
        }else{
            rec.setRnumbersStatus(2);
        }
        allRecNbrs.add(rec);
    }

    /**
     * @Description 标注用户购买的推荐号中奖情况，并判断一周内是否开出，否则退款
     * @title recUserNumber
     * @date 2021/3/15
     * @auther Administrator
     */
    private static List<UserNumbers> recUserNumber(List<UserNumbers> uRecs, String numbers, String term, List<UserNumbers> allUserNbs) {
        Integer hits = 3;
        for (UserNumbers uRec : uRecs) {
            if("0".equals(uRec.getNumbersType())){
                hits = 4;
            }else if("3".equals(uRec.getNumbersType())){
                hits = 5;
            }
            HashSet<String> set = new HashSet<>(Arrays.asList(numbers.split(",")));
            set.retainAll(Arrays.asList(uRec.getNumbersContent().split(",")));
            uRec.setNumbersHits(set.size());
            uRec.setNumbersTerm(term);
            uRec.setNumbersNbr(numbers);
            if (set.size() >= hits) {
                uRec.setNumbersStatus(1);
                allUserNbs.add(uRec);
            }else {
                uRec.setNumbersStatus(2);
            }
        }
        return uRecs;
    }
}
